﻿using System.Diagnostics;
using FytSoa.Application.Operator;
using FytSoa.Application.Sys;
using FytSoa.Common.Enum;
using FytSoa.Common.Utils;
using FytSoa.Domain.Core.Result;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Filters;
using System.Text.Json;
using FytSoa.Application;

namespace FytSoa.ApiService.Filters;

/// <summary>
/// 方法过滤器
/// </summary>
public class AopActionFilter:IAsyncActionFilter
{
    private readonly ISysLogService _logService;
    private IOperatorService _operatorService;
    public AopActionFilter (ISysLogService logService
        ,IOperatorService operatorService) {
        _logService = logService;
        _operatorService = operatorService;
    }
    public async  Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
    {
        if (SkipLogging(context))
        {
            await next();
            return;
        }
        
        if (!context.ModelState.IsValid)
        {
            context.Result = new JsonResult(JResult<string>.Error("参数不能为空~"));
            return;
        }
        //接口Type
            var type = (context.ActionDescriptor as ControllerActionDescriptor)?.ControllerTypeInfo.AsType();
            var module = type?.FullName;
            var arguments = context.ActionArguments;
            var parameters = string.Empty;
            if (arguments.Count > 0)
            {
                parameters = JsonSerializer.Serialize(arguments);
            }

            //开始计时
            var stopwatch = Stopwatch.StartNew();

            //Logger.Default.Info("Header-Token：" + context.HttpContext.Request.Headers["accessToken"]);
            //构建实体
            var logInfo = new SysLogDto()
            {
                Level = LogEnum.Info,
                LogType = LogTypeEnum.Operate,
                Module = type?.FullName,
                Method = context.HttpContext.Request.Method,
                OperateUser = _operatorService.User.Username,
                Parameters = parameters,
                IP = CommonUtils.GetIp(),
                Address = context.HttpContext.Request.Path + context.HttpContext.Request.QueryString,
                Browser = CommonUtils.GetBrowser(),
            };
            //Logger.Default.Info(JsonConvert.SerializeObject(logInfo));
            ActionExecutedContext result = null;
            result = await next();
            if (result.Exception != null && !result.ExceptionHandled)
            {
                logInfo.Message = result.Exception.Message;
            }
            stopwatch.Stop();
            logInfo.ExecutionDuration = Convert.ToInt32(stopwatch.Elapsed.TotalMilliseconds);
            var apiResult = result.Result switch
            {
                ObjectResult objectResult => JsonSerializer.Serialize(objectResult.Value),
                JsonResult jsonResult => JsonSerializer.Serialize(jsonResult.Value),
                ContentResult contentResult => contentResult.Content,
                _ => logInfo.ReturnValue
            };
            if (!string.IsNullOrEmpty(apiResult))
            {
                logInfo.ReturnValue = apiResult.Replace("\\", "").CutString(1000);
            }
            //保存日志信息
            await _logService.AddAsync(logInfo);
    }
    
    /// <summary>
    /// 判断类和方法头上的特性是否要进行Action拦截
    /// </summary>
    /// <param name="actionContext"></param>
    /// <returns></returns>
    private static bool SkipLogging(ActionContext actionContext)
    {
        return actionContext.ActionDescriptor.EndpointMetadata.Any(m =>
            m.GetType().FullName == typeof(NoAuditLogAttribute).FullName);
    }
}